#include "evaluate.h"

/**
 * Functions for calculating f-scores based on Result objects for different scenarios
 */

inline double calculateSingleFScore(const double& precision, const double& recall)
{
        if(precision == 0 || recall == 0)
        {
            return 0;
        }
        return 2*precision*recall/(precision+recall);
}

//Returns f-scores in order: q1 q2 q3 q4 q5 q6 q7 white red
inline std::vector<double> calculateFScores(Result& r)
{
   std::vector<double> Fscores(9,0);
   double precision;
   double recall;

   //qualities
   for (int i = 0; i < 7; i++)
   {
       precision = 0;
       recall = 0;
       if(r.correct_pre[i] != 0 && r.total_pre[i] != 0)
       {
            precision = (double)r.correct_pre[i]/r.total_pre[i];
       }
       if(r.correct_pre[i] != 0 && r.real_results[i] != 0)
       {
            recall = (double)r.correct_pre[i]/r.real_results[i];
       }
       Fscores[i] = calculateSingleFScore(precision, recall);
   }

   //types
   for (int i = 0; i < 2 ; i++)
   {
       precision = 0;
       recall = 0;
       if(r.correct_types[i] != 0 && r.total_pred_types[i] != 0)
       {
            precision = (double)r.correct_types[i]/r.total_pred_types[i];
       }
       if(r.correct_types[i] != 0 && r.total_types[i] != 0)
       {
            recall = (double)r.correct_types[i]/r.total_types[i];
       }
       Fscores[7+i] = calculateSingleFScore(precision, recall);
   }

   return Fscores;
}

//Returns f-scores for two step prediction in order: q1 q2 q3 q4 q5 q6 q7 white red
inline std::vector<double> calculateFScoresFromTwoStep(Result& all, Result& white, Result& red)
{
    std::vector<double> Fscores(9,0);
    double precision;
    double recall;

    int tp = 0; //true positives
    int fp_tp = 0; //false positives + true positives
    int fn_tp = 0; //false negatives + true positives

    //qualities
    for (int i = 0; i < 7; i++)
    {
        tp = white.correct_pre[i] + red.correct_pre[i];
        fp_tp = white.total_pre[i] + red.total_pre[i];
        fn_tp = white.real_results[i] + red.real_results[i];

        precision = 0;
        recall = 0;
        if(tp != 0 && fp_tp != 0)
        {
            precision = (double)tp/fp_tp;
        }
        if(tp != 0 && fn_tp != 0)
        {
            recall = (double)tp/fn_tp;
        }
        Fscores[i] = calculateSingleFScore(precision, recall);
    }

    //types
    for (int i = 0; i < 2 ; i++)
    {
        precision = 0;
        recall = 0;
        if(all.correct_types[i] != 0 && all.total_pred_types[i] != 0)
        {
             precision = (double)all.correct_types[i]/all.total_pred_types[i];
        }
        if(all.correct_types[i] != 0 && all.total_types[i] != 0)
        {
             recall = (double)all.correct_types[i]/all.total_types[i];
        }
        Fscores[7+i] = calculateSingleFScore(precision, recall);
    }

    return Fscores;
}

inline double calculateTotalFScore(Result& r)
{
    int tp = 0; //true positives
    int fp_tp = 0; //false positives + true positives
    int fn_tp = 0; //false negatives + true positives

    //qualities
    for (int i = 0; i < 7; i++)
    {
        tp += r.correct_pre[i];
        fp_tp += r.total_pre[i];
        fn_tp += r.real_results[i];
    }

    //types
    for (int i = 0; i < 2 ; i++)
    {
        tp += r.correct_types[i];
        fp_tp += r.total_pred_types[i];
        fn_tp += r.total_types[i];
    }

    double precision = (double)tp/fp_tp;
    double recall = (double)tp/fn_tp;

    return calculateSingleFScore(precision, recall);
}

//Calculates total f-score for only quality
inline double calculateTotalQualityFScore(Result& r)
{
    int tp = 0; //true positives
    int fp_tp = 0; //false positives + true positives
    int fn_tp = 0; //false negatives + true positives

    //qualities
    for (int i = 0; i < 7; i++)
    {
        tp += r.correct_pre[i];
        fp_tp += r.total_pre[i];
        fn_tp += r.real_results[i];
    }

    double precision = (double)tp/fp_tp;
    double recall = (double)tp/fn_tp;

    return calculateSingleFScore(precision, recall);
}

inline double calculateTotalFScoreFromTwoStep(Result& all, Result& white, Result& red)
{
    int tp = 0; //true positives
    int fp_tp = 0; //false positives + true positives
    int fn_tp = 0; //false negatives + true positives

    //qualities
    for (int i = 0; i < 7; i++)
    {
        tp += white.correct_pre[i];
        tp += red.correct_pre[i];
        fp_tp += white.total_pre[i];
        fp_tp += red.total_pre[i];
        fn_tp += white.real_results[i];
        fn_tp += red.real_results[i];
    }

    //types
    for (int i = 0; i < 2 ; i++)
    {
        tp += all.correct_types[i];
        fp_tp += all.total_pred_types[i];
        fn_tp += all.total_types[i];
    }

    double precision = (double)tp/fp_tp;
    double recall = (double)tp/fn_tp;

    return calculateSingleFScore(precision, recall);
}
